#include "FicheroDisperso.h"


#include <cstring>
#include <istream>
#include <cstdio>
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <string>



FicheroDisperso::FicheroDisperso():f(HashLibros){

	f.open(FicheroLibros,ios::in | ios::out);
	crear();
	cargar();
}


void FicheroDisperso::crear(){

	//Inicializa una cubeta vac�a
	for(int i=0;i<tamCubeta;i++){
		Cubeta.datos[i].ISBN[0]='\0';
		Cubeta.datos[i].titulo[0]='\0';
		Cubeta.datos[i].autores[0]='\0';
		Cubeta.datos[i].editorial[0]='\0';
		Cubeta.datos[i].anyo=0;
		Cubeta.datos[i].precioActual=0;
		Cubeta.tam=0;
                Cubeta.datos[i].pos=-1;
	}


     //Ahora creamos un fichero con tamFich cubetas vac�as.
     fstream f("isbn.dat",ios::out|ios::binary);
     f.open("isbn.dat",ios::in | ios::out);
     for(int i=0;i<tamTabla;i++){
		  f.write(reinterpret_cast<char *>(&Cubeta),sizeof(TCubeta));
	 }
}


bool FicheroDisperso::insertar(Libro &dato){

	libro nuevo;
	unsigned int clav,pos,i=0;

	strcpy(nuevo.titulo,dato.Obtener_Titulo().c_str());
	strcpy(nuevo.autores,dato.Obtener_Autores().c_str());
	strcpy(nuevo.editorial,dato.Obtener_Editorial().c_str());
	nuevo.anyo = dato.Obtener_Anyo();
	strcpy(nuevo.ISBN,dato.Obtener_ISBN().c_str());
	nuevo.precioActual = dato.Obtener_Precio();


	//Calculo la funcion de dispersion
	clav=atoi(nuevo.ISBN);
	pos = (clav) % tamTabla;

	//Creo el fichero hash
    fstream f("isbn.dat", ios::in | ios::out|ios::binary);
    f.open("isbn.dat",ios::in | ios::out);
    bool insertado=false;


    //Me situo a la cubeta a la que pertenece mi clave
    f.seekg(pos*sizeof(TCubeta), ios::beg);

    //Leo la cubeta
    f.read(reinterpret_cast<char *>(&Cubeta),sizeof(TCubeta));


    while((insertado==false)&&(i<tamCubeta)){
   		//Intento insertarla

    	if(Cubeta.datos[i].ISBN[0]=='\0'){

   			strcpy(Cubeta.datos[i].ISBN,nuevo.ISBN);
   			strcpy(Cubeta.datos[i].autores,nuevo.autores);
   			strcpy(Cubeta.datos[i].editorial,nuevo.editorial);
   			Cubeta.datos[i].precioActual=nuevo.precioActual;
   			strcpy(Cubeta.datos[i].titulo,nuevo.titulo);
   			Cubeta.datos[i].anyo=nuevo.anyo;
   			Cubeta.tam++;
   			i++;
   			insertado=true;

        }
        else{ //Caso de colision
            insertado=false;
            i++;
            if(Cubeta.tam==tamCubeta){
//   				cout<<"ERROR CUBETA LLENA"<<endl;


                    //caso en el que el dato no haya tenido ninguna colision
                    if(Cubeta.datos[i].pos==-1){
                        //Me situal al final del fichero saturado
                        fSaturada.seekg(sizeof(Libro), ios::end);

                        dato.meter_pos(-1);

                        fSaturada.write(reinterpret_cast<char *>(&dato),sizeof(Libro));
                        Cubeta.datos[i].pos=fSaturada.tellp();
                    }

                    else{
                        Libro *lib;
                        int long poscic =Cubeta.datos[i].pos;

                        //Me posiciono en la lugar donde esta la 1º colision
                        fSaturada.seekg(poscic*sizeof(Libro), ios::beg);
                        fSaturada.read(reinterpret_cast<char *>(lib),sizeof(Libro));

                        //Si hay una lista de colisiones la recorro
                        while(lib->Obtener_pos()!=-1){
                            poscic=lib->Obtener_pos();
                            fSaturada.seekg(poscic*sizeof(Libro), ios::beg);
                            fSaturada.read(reinterpret_cast<char *>(lib),pos*sizeof(Libro));
                        }

                        //Una vez que hemos llegado a la ultima posicion -1 escribo el dato y actualizo la cubeta
                         if(lib->Obtener_pos()==-1){
                            int long posic= fSaturada.tellg();
                            dato.meter_pos(posic);
                            fSaturada.write(reinterpret_cast<char *>(&dato),sizeof(Libro));
                            Cubeta.datos[i].pos=fSaturada.tellp();
                         }
                    }


                    }

            }
    }
   	

    //Me situo otra vez en la posicin correcta y escribo la cubeta en el fichero
     f.seekg(pos*sizeof(TCubeta), ios::beg);

     f.write(reinterpret_cast<char *>(&Cubeta),sizeof(TCubeta));


     f.close();
     return insertado;
}


bool FicheroDisperso::buscar(string &clave,libro &dato){

	bool encontrado=false;
	unsigned pos=0;
	unsigned int clav;
	string clave_dato;


	clav=atoi(clave.c_str());
	pos=(clav)%tamTabla;

	fstream f("isbn.dat", ios::in | ios::out |ios::binary);
        f.open("isbn.dat",ios::in | ios::out);
     //Me situo a la cubeta a la que pertenece mi clave
     f.seekg(pos*sizeof(TCubeta), ios::beg);

     //Leo la cubeta
      f.read(reinterpret_cast<char *>(&Cubeta),sizeof(TCubeta));

      //Busco si la clave se encuentra dentro de la cubeta
      for(unsigned i=0;i<tamCubeta && encontrado==false;i++){
    	  clave_dato=Cubeta.datos[i].ISBN;

            if(clave_dato==clave){
                  //Escribo en dato, el dato que tiene la cubeta
                  dato=Cubeta.datos[i];
                  encontrado=true;
            }
            else if(Cubeta.datos[i].pos!=-1){
             encontrado=recorrer_AreaSaturada(Cubeta.datos[i].pos,dato,clave);
            }

      }
       f.close();
       return encontrado;
}
bool FicheroDisperso::recorrer_AreaSaturada(int long pos,libro &dato,string &clave){
    bool encontrado;
    Libro *lib;
    int i;
    int poscic =pos;
    string clave_dato;

    //Me posiciono en la lugar donde esta la 1º colision
    fSaturada.seekg(pos*sizeof(Libro), ios::beg);
    fSaturada.read(reinterpret_cast<char *>(lib),sizeof(Libro));

    //Si hay una lista de colisiones la recorro
    while(lib->Obtener_pos()!=-1 && encontrado ==false){
        poscic=lib->Obtener_pos();
        fSaturada.seekg(poscic*sizeof(Libro), ios::beg);
        fSaturada.read(reinterpret_cast<char *>(lib),sizeof(Libro));

        clave_dato=Cubeta.datos[i].ISBN;

          if(clave_dato==clave){
                  //Escribo en dato, el dato que tiene la cubeta
                  dato=Cubeta.datos[i];
                  encontrado=true;
          }

    }

    //Una vez que hemos llegado a la ultima posicion -1 escribo el dato y actualizo la cubeta
     if(lib->Obtener_pos()==-1 && encontrado ==false){
        int long posic= fSaturada.tellg();
        dato.pos=posic;
        fSaturada.write(reinterpret_cast<char *>(&dato),sizeof(Libro));
        Cubeta.datos[i].pos=fSaturada.tellp();
          clave_dato=Cubeta.datos[i].ISBN;

          if(clave_dato==clave){
                  //Escribo en dato, el dato que tiene la cubeta
                  dato=Cubeta.datos[i];
                  encontrado=true;
          }

     }
 return encontrado;
}
void FicheroDisperso::cargar(){
	string titulo,autores,editorial,prec,anio,isbn,blanco;
	int anyo,i;
	float precio;

	//ifstream f("libros.txt");
        fstream f("libros.txt", ios::in | ios::out |ios::binary);
        f.open("libros.txt",ios::in | ios::out);
	if(f==NULL){cout<<"aki";
		//throw ErrArchNoAbierto();
	}else{

		while(!f.eof()){
			getline(f,titulo);
			getline(f,autores);
			getline(f,anio);
			getline(f,editorial);
			getline(f,isbn);
			getline(f,prec);
			getline(f,blanco);
			anyo=atoi(anio.c_str());
			precio=atof(prec.c_str());
			Libro nuevo(titulo,autores,editorial,anyo,isbn,precio);
			i++;
			insertar(nuevo);
		}
	}

	f.close();
}


